package jdk.java.util.concurrent.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
@Slf4j(topic = "MyLockTest")
public class MyLockTest {

    public static void main(String[] args) throws InterruptedException {

        /*
         java.util.concurrent.locks.Lock接口中，4种获取锁方式比较：
                1）lock(), 拿不到lock就不罢休，不然线程就一直block。 比较无赖的做法。

                2）tryLock()，马上返回，拿到lock就返回true，不然返回false。 比较潇洒的做法。

                3）带时间限制的tryLock()，拿不到lock，就等一段时间，超时返回false。比较聪明的做法。

                4）lockInterruptibly()就稍微难理解一些。先说说线程的打扰机制，每个线程都有一个 打扰 标志。
                这里分两种情况，
                    1. 线程在sleep或wait,join， 此时如果别的进程调用此进程的 interrupt（）方法，
                    此线程会被唤醒并被要求处理InterruptedException；(thread在做IO操作时也可能有类似行为，
                    见java thread api)
                    2. 此线程在运行中， 则不会收到提醒。但是 此线程的 “打扰标志”会被设置， 可以通过isInterrupted()查看并 作出处理。
                    lockInterruptibly()和上面的第一种情况是一样的， 线程在请求lock并被阻塞时，
                    如果被interrupt，则“此线程会被唤醒并被要求处理InterruptedException”。并且如果线程已经被interrupt，
                    再使用lockInterruptibly的时候，此线程也会被要求处理interruptedException
         */
        log.info("MyLock.SEX_MAN = " + MyLock.SEX_MAN); // 仅仅是测试用的,测试需要review，哈哈
        MyLock lock = new MyLock();
        Thread thread1 = new Thread(()->{
            try {
                lock.lock();
                log.info("ThreadName = " + Thread.currentThread().getName()+" acquire lock");
            } finally {
                long time = 2L;
                try {
                    TimeUnit.SECONDS.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lock.unlock();
                log.info(time+"秒后 ThreadName = " + Thread.currentThread().getName()+" release lock");
            }

        },"阻塞锁线程1");
        Thread thread2 = new Thread(()->{
            //1.永远等待
            //lock.lock();
            //2.线程中断，锁不会等待
//            try {
//                lock.lockInterruptibly();
//                log.info("ThreadName = " + Thread.currentThread().getName()+" acquire lock");
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            //3.尝试获取锁，获取不到也继续执行
            //lock.tryLock();
            //4.有限时间尝试获取锁，等待时间结束后，获取不到也继续执行
            try {
                if(lock.tryLock(3000, TimeUnit.MILLISECONDS)){
                    log.info("ThreadName = " + Thread.currentThread().getName()+" acquire lock");
                }else{
                    log.info("ThreadName = " + Thread.currentThread().getName()+" give up acquire lock");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        },"阻塞锁线程2");


        thread1.start();
        Thread.sleep(5L); //保证线程1先获取锁
        thread2.start();
//        log.info("主线程休眠5s后，打断阻塞线程2抛出异常不再等待");
//        Thread.sleep(5000L);
//        thread2.interrupt();
        log.info("main thread end");
        /*
            1.被阻塞的线程2如果是通过lock.lock();加锁  效果如下：
                主线程休眠5s后，打断阻塞线程2抛出异常不再等待
                Thread.currentThread().getName() = 阻塞锁线程1 acquire lock
                main thread end
            1.被阻塞的线程2如果是通过lock.lockInterruptibly();加锁  效果如下：
            主线程休眠5s后，打断阻塞线程2抛出异常不再等待
            main thread end
            java.lang.InterruptedException
                at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
                at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
                at jdk.java.util.concurrent.aqs.MyLock.lockInterruptibly(MyLock.java:66)
                at jdk.java.util.concurrent.aqs.MyLockTest.lambda$main$1(MyLockTest.java:17)
                at java.lang.Thread.run(Thread.java:748)
         */
    }
}
